import EditorEmb from "./DesignEditorEmb.js";
import DesignResource from "./DesignResource.js";

let Fabric = null;

class Editor {
    // 构造函数
    constructor(FabricClass, element, option = {}) {
        // 容器嵌套逻辑，包括画布、映射器、设计区、滤镜、遮罩
        // 最外层容器是画布
        // 设计器映射到映射器上展示

        !Fabric && FabricClass && (Fabric = FabricClass);

        // 画布相关
        this.canvas_scale = option.canvas_scale || 1;
        this.canvas_name = option.canvas_name;
        this.canvas_width = option.canvas_width;
        this.canvas_height = option.canvas_height;
        this.canvas_model = option.canvas_model || "simple"; // [simple|print] 精简模式、打印模式
        this.type = option.type;

        // 图层
        this.stage = new Map();
        // 渲染器
        this.cache = {
            string: "",
            status: "inited",
            loop: [], // 渲染队列
        };

        this.onUpdate = option.onUpdate || null;
        this.layers = option.design_layers || [];
        this.fontLoop = new Map();

        // 纯展示用
        this.fabric = new Fabric.StaticCanvas(element || null, {
            enableRetinaScaling: false,
            width: this.canvas_width * this.canvas_scale,
            height: this.canvas_height * this.canvas_scale,
        });

        // 文字变形方案
        // 存在缩放问题
        // https://stackoverflow.com/questions/19726778/create-valley-text-text-with-curve-in-fabric-js
        // http://jsfiddle.net/NHs8t/
        // http://jsfiddle.net/7vcgoydr/1/
    }

    reset(option) {
        this.canvas_scale = option.canvas_scale || 1;
        this.canvas_name = option.canvas_name;
        this.canvas_width = option.canvas_width;
        this.canvas_height = option.canvas_height;
        this.canvas_model = option.canvas_model || "simple"; // [simple|print] 精简模式、打印模式

        this.onUpdate = option.onUpdate || null;

        this.layers = option.design_layers || [];
        this.fabric.setWidth(this.canvas_width * this.canvas_scale);
        this.fabric.setHeight(this.canvas_height * this.canvas_scale);
    }

    // 更新元素
    updateLayer(layer) {
        // 可能内容不变，可不用更新
        let stage = this.stage.get(layer);

        if (!stage) {
            console.log(layer);
            // 没有数据，不用管
            return Promise.reject("layer must set in stage map");
        } else if (layer.type == "image") {
            // fabric默认添加图片到画布的时候，是使用图片资源的本身真实宽高来绘制的
            let image = stage._element || { width: layer.w, height: layer.h };
            // let imageScale = Math.max(layer.imageW/image.width, layer.imageH/image.height);
            let canvasScale =
                this.canvas_scale /
                Math.max(image.width / layer.w, image.height / layer.h);

            stage.set({
                left: (layer.x + 0.5 * layer.w) * this.canvas_scale,
                top: (layer.y + 0.5 * layer.h) * this.canvas_scale,
                width: image.width,
                height: image.height,
                angle: layer.rotate,
                scaleX: canvasScale,
                scaleY: canvasScale,
                flipX: layer.flipX,
                flipY: layer.flipY,
                backgroundColor: stage._element ? null : "#f2f2f2",
            });

            if (stage._element) {
                return Promise.resolve();
            } else {
                // 没有图片的，先临时渲染一次
                const doRender = () => {
                    // 如果有监听
                    if (this.onUpdate) {
                        this.fabric.renderAll();
                        this.onUpdate(this.fabric);
                    }
                };

                // 加载小图
                const loadMinImage = () => {
                    let option = {
                        type: "fastest",
                        form: "materials",
                    };
                    return DesignResource.loadImage(layer.url, option).then(
                        (img) => {
                            // 没有节点，才渲染
                            if (!stage._element) {
                                stage.set({ backgroundColor: null });
                                stage.setElement(img);
                                return this.updateLayer(layer).then(() =>
                                    doRender()
                                );
                            } else {
                                return Promise.resolve();
                            }
                        }
                    );
                };

                // 加载大图
                const loadBigImage = () => {
                    let option = {
                        type: this.canvas_model,
                        form: "materials",
                    };
                    return DesignResource.loadImage(layer.url, option).then(
                        (img) => {
                            // 没有不管有没有节点，都渲染
                            stage.set({ backgroundColor: null });
                            stage.setElement(img);
                            return this.updateLayer(layer);
                        }
                    );
                };

                doRender();
                return Promise.all([loadMinImage(), loadBigImage()]);
            }
        } else if (layer.type == "text") {
            let scale = this.canvas_scale;

            let fontFamily = layer.font_family || "Arial";
            let fontSize = layer.font_size * scale;
            let lineHeight = layer.font_size * scale;
            let charSpacing = layer.letter_spacing * 1000;

            let shadow = null;

            if (layer.shadow_distance && layer.shadow_color) {
                // 模糊度
                let blur = layer.shadow_blur * layer.font_size * scale;
                // 偏移距离
                let distance = layer.shadow_distance * layer.font_size * scale;
                // 偏移角度
                let radians =
                    ((layer.shadow_angle + -layer.rotate) % 360) *
                    (Math.PI / 180);

                shadow = new Fabric.Shadow({
                    blur: blur,
                    offsetX: Math.sin(radians) * distance,
                    offsetY: Math.cos(radians) * distance,
                    nonScaling: true,
                    affectStroke: true,
                    color: layer.shadow_color,
                });
            }

            // 外部容器位置
            stage.set({
                left: (layer.x + 0.5 * layer.w) * scale,
                top: (layer.y + 0.5 * layer.h) * scale,
                width: layer.w * scale,
                height: layer.h * scale,
                angle: layer.rotate,
                flipX: layer.flipX,
                flipY: layer.flipY,
                text: String(layer.text),
                fill: layer.font_color,
                fontSize: fontSize,
                lineHeight: lineHeight,
                charSpacing: charSpacing,
                paintFirst: "stroke",
                stroke: layer.outline_color,
                strokeWidth: layer.outline_weight * layer.font_size * scale,
                shadow: shadow,
                fontFamily: fontFamily,
            });

            if (DesignResource.getFontByCache(fontFamily)) {
                // 字体已加载
                return Promise.resolve();
            } else {
                // 字体未加载
                // 先渲染一次
                if (this.onUpdate) {
                    this.fabric.renderAll();
                    this.onUpdate(this.fabric);
                }
                return DesignResource.loadFont(fontFamily).then((font) => {
                    if (layer.font_family == fontFamily) {
                        Fabric.util.clearFabricFontCache();
                        return this.updateLayer(layer);
                    } else {
                        return Promise.resolve();
                    }
                });
            }
        } else if (layer.type == "emb") {
            stage.updateLayer(this.fabric, layer, this.canvas_scale);

            this.fabric.renderAll();
            this.onUpdate(this.fabric);
            return Promise.resolve();

            // let image = stage._element || { width: layer.w, height: layer.h };
            // let imgSale = Math.max(
            //     image.width / layer.w,
            //     image.height / layer.h
            // );
            // let canvasScale = this.canvas_scale / imgSale;
            // let keys = ["colors", "stitches"];

            // let change = keys.find((key) => layer[key] != stage[key]);

            // stage.set({
            //     left: (layer.x + 0.5 * layer.w) * this.canvas_scale,
            //     top: (layer.y + 0.5 * layer.h) * this.canvas_scale,
            //     width: image.width,
            //     height: image.height,
            //     angle: layer.rotate,
            //     scaleX: canvasScale,
            //     scaleY: canvasScale,
            //     originX: "center",
            //     originY: "center",
            // });

            // stage.colors = layer.colors;
            // stage.stitches = layer.stitches;

            // if (change) {
            //     const colors = layer.colors;
            //     // 先渲染一次
            //     this.onUpdate(this.fabric);
            //     return DesignResource.loadEmb(layer).then((canvas) => {
            //         stage.colors == colors && stage.setElement(canvas);
            //         return this.updateLayer(layer);
            //     });
            // } else {
            //     return Promise.resolve();
            // }
        } else {
            return Promise.reject("unknown type" + JSON.stringify(layer));
        }
    }

    // 插入元素
    insertLayer(layer) {
        if (layer.type == "image") {
            // 没有链接，或是没有加载资源，或是资源加载未完成
            // 加载中的效果

            let image = DesignResource.getImageByCache(layer.url, {
                type: this.canvas_model,
                form: "materials",
            });
            let stage = new Fabric.Image(image, {
                originX: "center",
                originY: "center",
            });

            this.fabric.add(stage);
            this.stage.set(layer, stage);

            return this.updateLayer(layer);
        } else if (layer.type == "text") {
            let text = new Fabric.Text(layer.text, {
                originX: "center",
                originY: "center",
                textAlign: "center",
            });

            this.fabric.add(text);
            this.stage.set(layer, text);
            return this.updateLayer(layer);
        } else if (layer.type == "emb") {
            this.stage.set(layer, new EditorEmb(Fabric, this.fabric, layer));
            return this.updateLayer(layer);
        } else {
            return Promise.reject("unknown type" + JSON.stringify(layer));
        }
    }

    // 删除元素
    removeLayer(layer) {
        let stage = this.stage.get(layer);
        if (!stage) {
            return Promise.reject();
        } else if (layer.type == "emb") {
            // 刺绣
            const dsts = Array.from(stage.cache.keys());
            dsts.map((i) => stage.removeDst(this.fabric, layer, i));
            this.stage.delete(layer);
            return Promise.resolve();
        } else {
            this.stage.delete(layer);
            this.fabric.remove(stage);
            return Promise.resolve();
        }
    }

    // 渲染，事务处理，按顺序执行
    renderLayers(option) {
        let layers = option && option.map ? option : this.layers;
        let string = JSON.stringify({
            canvas_scale: this.canvas_scale,
            canvas_width: this.canvas_width,
            canvas_height: this.canvas_height,
            canvas_model: this.canvas_model,
            layers: layers,
        });

        if (!this.fabric) {
            // 没有canvas
            return Promise.reject("fabric Uninitialized");
        } else if (
            this.cache.string == string &&
            this.cache.status == "complete"
        ) {
            // 相同
            // 渲染
            this.fabric.renderAll();
            return Promise.resolve(this.fabric);
        } else if (
            this.cache.string == string &&
            this.cache.status == "loading"
        ) {
            // 加载中
            return new Promise((resolve, reject) => {
                this.cache.loop.push((fabric) => {
                    if (fabric) {
                        resolve(fabric);
                    } else {
                        reject();
                    }
                });
            });
        } else {
            return new Promise((resolve, reject) => {
                let promises = [];

                // 新增或修改
                layers.map((layer, index) => {
                    if (this.stage.get(layer)) {
                        promises.push(this.updateLayer(layer));
                    } else {
                        // 添加
                        promises.push(this.insertLayer(layer));
                    }
                });

                // 删除
                this.stage.forEach((stage, layer) => {
                    if (layers.indexOf(layer) >= 0) {
                        // 存在的，不用删除
                    } else {
                        promises.push(this.removeLayer(layer));
                    }
                });

                this.layers = layers;
                this.cache.status = "loading";
                this.cache.string = string;

                Promise.all(promises)
                    .then((e) => {
                        // 图层排序
                        let index = 0;
                        layers.map((layer) => {
                            if (layer.type == "emb") {
                                const emb = this.stage.get(layer) || {};
                                const list = emb.list || [];

                                list.map((dst) => {
                                    this.fabric.moveTo(dst, index);
                                    index += 1;
                                });
                            } else {
                                this.fabric.moveTo(
                                    this.stage.get(layer),
                                    index
                                );
                                index += 1;
                            }
                        });

                        // 渲染
                        this.fabric.renderAll();

                        resolve(this.fabric);

                        this.onUpdate && this.onUpdate(this.fabric);
                        this.cache.status = "complete";
                        this.cache.loop.map((cb) => cb(this.fabric));
                        this.cache.loop = [];
                    })
                    .catch((error) => {
                        console.log(error);
                        reject(this.fabric);
                        this.cache.status = "error";
                        this.cache.loop.map((cb) => cb());
                        this.cache.loop = [];
                    });
            });
        }
    }

    // 销毁
    destroy() {
        // this.pixi.destroy();
    }
}

export default Editor;
